#pragma once

#include <vector>
#include <semaphore.h>
#include <pthread.h>

template<class T>
class ringqueue
{
private:
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
public:
    ringqueue(int cap) :_cap(cap), _ring_queue(cap), _producer_pos(0), _consumer_pos(0)
    {
        pthread_mutex_init(&_producer_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);

        sem_init(&_room, 0, cap);
        sem_init(&_data, 0, 0);
    }

    void Enqueue(T& in)
    {
        P(_room);
        pthread_mutex_lock(&_producer_mutex);
        // 走到这里就一定获取到了空间资源
        _ring_queue[_producer_pos++] = in;
        _producer_pos %= _cap;
        pthread_mutex_unlock(&_producer_mutex);
        V(_data);
    }

    void Pop(T* out)
    {
        P(_data);
        pthread_mutex_lock(&_consumer_mutex);
        *out = _ring_queue[_consumer_pos++];
        _consumer_pos %= _cap;
        pthread_mutex_unlock(&_consumer_mutex);
        V(_room);
    }

    ~ringqueue(){
        pthread_mutex_destroy(&_producer_mutex);
        pthread_mutex_destroy(&_consumer_mutex);

        sem_destroy(&_room);
        sem_destroy(&_data);
    }
private:
    vector<T> _ring_queue;
    int _cap;

    int _producer_pos;
    int _consumer_pos;

    sem_t _room; // producer
    sem_t _data; // consumer

    pthread_mutex_t _producer_mutex;
    pthread_mutex_t _consumer_mutex;
};